const mimeMap = require('./mimeMap')

function FormData() {
	let fileManager = wx.getFileSystemManager();
	let data = {};
	let files = [];

	this.append = (name, value) => {
		data[name] = value;
		return true;
	}

	this.appendFile = (name, path, fileName) => {
		let buffer = fileManager.readFileSync(path);
		if (Object.prototype.toString.call(buffer).indexOf("ArrayBuffer") < 0) {
			return false;
		}

		if (!fileName) {
			fileName = getFileNameFromPath(path);
		}

		files.push({
			name: name,
			buffer: buffer,
			fileName: fileName
		});
		return true;
	}

	this.getData = () => convert(data, files)
}

function getFileNameFromPath(path) {
	let idx = path.lastIndexOf("/");
	return path.substr(idx + 1);
}

function convert(data, files) {
	let boundaryKey = 'wxmpFormBoundary' + randString(); // 数据分割符，一般是随机的字符串
	let boundary = '--' + boundaryKey;
	let endBoundary = boundary + '--';

	let postArray = [];
	//拼接参数
	if (data && Object.prototype.toString.call(data) == "[object Object]") {
		for (let key in data) {
			postArray = postArray.concat(formDataArray(boundary, key, data[key]));
		}
	}
	//拼接文件
	if (files && Object.prototype.toString.call(files) == "[object Array]") {
		for (let i in files) {
			let file = files[i];
			postArray = postArray.concat(formDataArray(boundary, file.name, file.buffer, file.fileName));
		}
	}
	//结尾
	let endBoundaryArray = [];
	endBoundaryArray.push(...endBoundary.toUtf8Bytes());
	postArray = postArray.concat(endBoundaryArray);
	return {
		contentType: 'multipart/form-data; boundary=' + boundaryKey,
		buffer: new Uint8Array(postArray).buffer
	}
}

function randString() {
	var result = '';
	var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
	for (var i = 17; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
	return result;
}

function formDataArray(boundary, name, value, fileName) {
	let dataString = '';
	let isFile = !!fileName;

	dataString += boundary + '\r\n';
	dataString += 'Content-Disposition: form-data; name="' + name + '"';
	if (isFile) {
		dataString += '; filename="' + fileName + '"' + '\r\n';
		dataString += 'Content-Type: ' + getFileMime(fileName) + '\r\n\r\n';
	} else {
		dataString += '\r\n\r\n';
		dataString += value;
	}

	var dataArray = [];
	dataArray.push(...dataString.toUtf8Bytes());

	if (isFile) {
		let fileArray = new Uint8Array(value);
		dataArray = dataArray.concat(Array.prototype.slice.call(fileArray));
	}
	dataArray.push(..."\r".toUtf8Bytes());
	dataArray.push(..."\n".toUtf8Bytes());

	return dataArray;
}

function getFileMime(fileName) {
	let idx = fileName.lastIndexOf(".");
	let mime = mimeMap[fileName.substr(idx)];
	return mime ? mime : "application/octet-stream"
}

String.prototype.toUtf8Bytes = function() {
	var str = this;
	var bytes = [];
	for (var i = 0; i < str.length; i++) {
		bytes.push(...str.utf8CodeAt(i));
		if (str.codePointAt(i) > 0xffff) {
			i++;
		}
	}
	return bytes;
}

String.prototype.utf8CodeAt = function(i) {
	var str = this;
	var out = [],
		p = 0;
	var c = str.charCodeAt(i);
	if (c < 128) {
		out[p++] = c;
	} else if (c < 2048) {
		out[p++] = (c >> 6) | 192;
		out[p++] = (c & 63) | 128;
	} else if (
		((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
		((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
		// Surrogate Pair
		c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
		out[p++] = (c >> 18) | 240;
		out[p++] = ((c >> 12) & 63) | 128;
		out[p++] = ((c >> 6) & 63) | 128;
		out[p++] = (c & 63) | 128;
	} else {
		out[p++] = (c >> 12) | 224;
		out[p++] = ((c >> 6) & 63) | 128;
		out[p++] = (c & 63) | 128;
	}
	return out;
};

module.exports = FormData
